<template>
	<view class="pb-150">
		<image src="/static/dingbu.png" class="mine-navbar-bg" :style="{ height: navbarHeight + 'rpx' }"
			mode="aspectFill">
		</image>
		<u-navbar title="产品监测任务下发" :autoBack="true" leftIconColor="#fff" bgColor="transparent"
			:titleStyle="{ color: '#fff' }" safeAreaInsetTop placeholder></u-navbar>

		<view class="content">
			<view class="info-card">
				<view class="info-row">
					<text class="label">监测年份：</text>
					<text class="value" @tap.stop.prevent="openYearPicker">{{ submitForm.year || (new
						Date().getFullYear()) + '年' }}</text>
				</view>
				<view class="info-row">
					<text class="label">监测类别：</text>
					<text class="value" @tap.stop.prevent="openCategoryPicker">{{ submitForm.category || '监测抽检'
						}}</text>
				</view>
				<view class="info-row">
					<text class="label">任务级别：</text>
					<text class="value" @tap.stop.prevent="openLevelPicker">{{ submitForm.level || '请选择' }}</text>
				</view>
			</view>

			<!-- 上传区域 -->
			<view class="upload-section" style="margin: 20rpx 0;" v-if="isEditMode">
				<view class="form-item">
					<text class="form-label">判定标准上传</text>
					<view class="upload-controls">
						<u-button class="button" type="primary" size="small" @click="handleUpload">点击上传</u-button>
						<text class="upload-note">注:支持.xlsx、xls、docx文件</text>
					</view>

					<view v-if="uploadedFiles.length > 0" class="file-list">
						<view v-for="(file, index) in uploadedFiles" :key="index" class="file-item">
							<view class="file-info">
								<u-icon name="file-text" size="32" color="#007AFF"></u-icon>
								<text class="file-name">{{ file.name }}</text>
								<text class="file-size">{{ formatSize(file.size) }}</text>
							</view>
							<view class="file-status">
								<text v-if="file.status === 'success'" class="status-success">{{
									getStatusText(file.status) }}</text>
								<text v-else-if="file.status === 'progress'" class="status-progress">{{
									getStatusText(file.status) }}
									{{ file.progress }}%</text>
								<text v-else-if="file.status === 'fail'" class="status-fail">{{
									getStatusText(file.status) }}</text>
								<text v-else class="status-pending">{{ getStatusText(file.status) }}</text>
							</view>
							<u-icon name="close" size="24" color="#999" @click="removeFile(index)"></u-icon>
						</view>
					</view>
				</view>
			</view>

			<view class="section">
				<view class="section-title">
					<view class="dot"></view>检验方法和依据
				</view>
				<view class="allocations" v-if="allocationsFromUpload && allocations.length > 0">
					<view class="alloc-group" v-for="(g, gi) in allocations" :key="gi">
						<view class="group-header">{{ g.org }}</view>
						<view class="alloc-table">
							<view class="table-row table-head">
								<view class="cell" v-for="(col, ci) in g.columns" :key="ci">{{ col }}</view>
								<view class="cell">操作</view>
							</view>
							<view class="table-row" v-for="(row, ri) in g.rows" :key="ri">
								<view class="cell" v-for="(col, ci) in g.columns" :key="ci">
									<template v-if="row.editing && !(taskId && !isEditMode)">
										<!-- 合计列不可编辑，仅显示 -->
										<template v-if="isTotalColumn(col)">{{ row[col] }}</template>
										<template v-else>
											<!-- 保持原始显示格式，统一使用文本输入，避免自动格式化数字 -->
											<u-input class="edit-input" type="text" :value="row[col]"
												@change="onRowFieldChange($event, g, ri, col)" />
										</template>
									</template>
									<template v-else>{{ row[col] }}</template>
								</view>
								<view class="cell">
									<template v-if="taskId && !isEditMode">
										<text class="readonly-text">-</text>
									</template>
									<template v-else-if="row.editing">
										<u-button size="mini" plain @click="saveRowEdit(g, ri)">保存</u-button>
										<u-button size="mini" plain type="error"
											@click="cancelRowEdit(g, ri)">取消</u-button>
									</template>
									<template v-else>
										<text class="link" @click="startEditRow(g, ri)">修改</text>
									</template>
								</view>
							</view>
							<!-- <view class="table-row table-sum">
								<view class="cell">总计</view>
								<view class="cell" v-for="(col,ci) in g.columns" :key="ci">{{ (g.sum && g.sum[col]) !== undefined ? g.sum[col] : '-' }}</view>
								<view class="cell">-</view>
							</view> -->
						</view>
					</view>
				</view>
			</view>



			<view class="actions" v-if="!(taskId && !isEditMode)">
				<u-button type="primary" style="background: #11ac5e;border: 0;border-radius: 20rpx;"
					@click="handleConfirmSubmit">确认</u-button>
			</view>
		</view>

		<!-- 上传插件引用 -->
		<lsj-upload ref="lsjUploadRef"></lsj-upload>

		<!-- pickers -->
		<u-picker :show="showYearPicker" :columns="[yearOptions]"
			:defaultIndex="[yearOptions.indexOf(new Date().getFullYear().toString())]" @confirm="onYearConfirm"
			@cancel="onPickerCancel('year')"></u-picker>
		<u-picker :show="showCategoryPicker" :columns="[categoryOptions]" @confirm="onCategoryConfirm"
			@cancel="onPickerCancel('category')"></u-picker>
		<u-picker :show="showLevelPicker" :columns="[levelOptions]" @confirm="onLevelConfirm"
			@cancel="onPickerCancel('level')"></u-picker>
	</view>

</template>

<script>
import request from '@/utils/request'
import config from '@/config.js'
import { monitorTask, monitorTaskdetail, provicemonitorTaskdetail, shimonitorTaskdetail } from '@/api/sylin/index.js'
export default {
	data() {
		return {
			customNavbarHeight: null,
			submitForm: {
				year: '',
				category: '',
				level: '省级'
			},
			detectionTypeMap: {},
			detectionTypeDictType: 'product_monitor_type',
			levelMap: {},
			taskId: '',
			isEditMode: false,
			userType: '1',
			isLevelReadonly: false,
			uploadedFiles: [],
			showYearPicker: false,
			showCategoryPicker: false,
			showLevelPicker: false,
			yearOptions: (() => {
				const currentYear = new Date().getFullYear()
				const years = []
				for (let i = currentYear + 20; i >= currentYear - 20; i--) years.push(String(i))
				return years
			})(),
			// 默认不包含“全部”，字典加载后会替换为后端值
			categoryOptions: ['监督抽检', '评价性抽检', '风险监测'],
			levelOptions: ['全部', '省级', '市级', '区县级'],
			products: [{
				name: '苹果',
				rules: [{
					item: '铅',
					limit: '0.2',
					standard: 'GB2762-2022',
					method: 'GB 5009-12-2023'
				}, {
					item: '镉',
					limit: '0.2',
					standard: 'GB2762-2022',
					method: 'GB 5009-12-2023'
				}, {
					item: '',
					limit: '',
					standard: '',
					method: ''
				}]
			},
			{
				name: '梨',
				rules: [{
					item: '铅',
					limit: '0.2',
					standard: 'GB2762-2022',
					method: 'GB 5009-12-2023'
				}, {
					item: '镉',
					limit: '0.2',
					standard: 'GB2762-2022',
					method: 'GB 5009-12-2023'
				}, {
					item: '',
					limit: '',
					standard: '',
					method: ''
				}]
			}
			]
			// 示例：按承检机构分组的分配表，用于渲染页面内表格（可替换为后端数据）
			,
			allocations: [],
			allocationsFromUpload: false

		}

	},
	computed: {
		navbarHeight() {
			if (this.customNavbarHeight) return this.customNavbarHeight
			const systemInfo = uni.getSystemInfoSync()
			const statusBarHeightRpx = systemInfo.statusBarHeight * 2
			const navbarHeightRpx = 44 * 2
			return statusBarHeightRpx + navbarHeightRpx
		}
	},
	async onLoad(options) {
		// 确保年份有默认值（与 picker 列表项格式一致）
		const y = (typeof uni !== 'undefined' && uni.getStorageSync) ? uni.getStorageSync('defaultYear') : ''
		if (y) this.submitForm.year = y
		if (!this.submitForm.year) this.submitForm.year = String(new Date().getFullYear())

		try {
			let ut = ''
			if (typeof uni !== 'undefined' && uni.getStorageSync) ut = uni.getStorageSync('userType')
			else if (typeof localStorage !== 'undefined') ut = localStorage.getItem('userType')
			if (!ut) ut = '1'
			this.userType = String(ut)
			switch (String(this.userType)) {
				case '1':
					this.submitForm.level = '省级';
					this.isLevelReadonly = true;
					break
				case '2':
					this.submitForm.level = '市级';
					this.isLevelReadonly = true;
					break
				case '3':
					this.submitForm.level = '区县级';
					this.isLevelReadonly = true;
					break
				default:
					this.isLevelReadonly = false
			}
		} catch (e) {
			console.warn('read userType error', e)
		}

		this.loadDetectionDict()
		this.loadLevelDict()
		// 先加载字典，再根据路由参数加载任务详情
		await this.loadDetectionDict()
		await this.loadLevelDict()
		// 读取路由参数（taskId/edit）
		if(options.edit) {
			this.isEditMode = options.edit === '1' || options.edit === 'true' || options.edit === 1
		}
		if (options && options.taskId) {
			this.taskId = options.taskId
			// 加载任务详情并填充页面
			await this.loadTaskDetail()
		}
		// 若字典尚未返回，先使用本地默认列表的首项作为初始值，避免模板显示但表单值为空导致校验失败
		if (!this.submitForm.category && Array.isArray(this.categoryOptions) && this.categoryOptions.length > 0) {
			this.submitForm.category = this.categoryOptions[0]
		}
	},


	methods: {
		// 根据 taskId / userType / isEditMode 加载任务详情并填充表单
		async loadTaskDetail() {
			if (!this.taskId) return
			try {
				let res
				// 编辑模式下根据 userType 使用不同接口
				res = await monitorTaskdetail(this.taskId)
				const payload = res && (res.data || res)
				if (!payload) return
				// 填充基础字段
				this.submitForm.year = String(payload.year || payload.monitorYear || payload.detectionYear || this.submitForm.year)
				// detectionType 可能为 key，需要转换为 label
				if (payload.detectionType) {
					this.submitForm.category = this.detectionTypeMap[payload.detectionType] || payload.detectionType
				}
				if (payload.detectionLevel) {
					this.submitForm.level = this.levelMap[payload.detectionLevel] || payload.detectionLevel
				}
				// 处理上传返回的数据字段（可能为 JSON 字符串）
				let arr = null
				
				// 优先使用 monitorTaskDetails1 中的数据
				console.log('payload.monitorTaskDetails1:', payload.monitorTaskDetails1)
				if (payload.monitorTaskDetails1 && Array.isArray(payload.monitorTaskDetails1) && payload.monitorTaskDetails1.length > 0) {
					const detail = payload.monitorTaskDetails1[0]
					console.log('monitorTaskDetails1[0]:', detail)
					if (detail.detectionProject) {
						console.log('detail.detectionProject:', detail.detectionProject)
						try { 
							const parsedData = typeof detail.detectionProject === 'string' ? JSON.parse(detail.detectionProject) : detail.detectionProject
							console.log('解析后的数据:', parsedData)
							// 如果是单个对象，转换为数组
							arr = Array.isArray(parsedData) ? parsedData : [parsedData]
							console.log('最终arr:', arr)
						} catch (e) { 
							console.error('解析 monitorTaskDetails1.detectionProject 失败:', e)
							arr = null 
						}
					}
				}
				
				// 如果 monitorTaskDetails1 没有数据，再尝试使用 detectionProject
				if (!arr && payload.detectionProject) {
					try { arr = typeof payload.detectionProject === 'string' ? JSON.parse(payload.detectionProject) : payload.detectionProject } catch (e) { arr = null }
				}
				
				// 最后尝试使用 allocationInfo
				if (!arr && payload.allocationInfo) {
					try { arr = typeof payload.allocationInfo === 'string' ? JSON.parse(payload.allocationInfo) : payload.allocationInfo } catch (e) { arr = null }
				}
				if (Array.isArray(arr) && arr.length > 0) {
					const parsed = this.parseUploadResult(arr)
					if (parsed && parsed.length > 0) {
						this.allocations = parsed
						this.allocations.forEach(g => this.recalcGroupSum(g))
						this.allocationsFromUpload = true
					}
				}
				// 若后端返回了附件信息，可将其映射到 uploadedFiles（按需）
				if (payload.files && Array.isArray(payload.files)) {
					this.uploadedFiles = payload.files.map(f => ({ name: f.name || f.fileName, size: f.size || 0, status: 'success', response: f }))
				}
			} catch (err) {
				console.error('loadTaskDetail error', err)
			}
		},
		openYearPicker() {
			if (this.taskId && !this.isEditMode) return
			this.showYearPicker = true
		},
		openCategoryPicker() {
			if (this.taskId && !this.isEditMode) return
			this.showCategoryPicker = true
		},
		openLevelPicker() {
			if (this.isLevelReadonly) {
				uni.showToast({
					title: '任务级别由你的用户身份决定，无法修改',
					icon: 'none'
				});
				return
			}
			if (this.taskId && !this.isEditMode) return
			this.showLevelPicker = true
		},
		handleUpload() {
			if (this.taskId && !this.isEditMode) return
			if (!this.$refs.lsjUploadRef) return
			this.$refs.lsjUploadRef.chooseFile({
				count: 5,
				size: 10,
				multiple: true,
				formats: 'xlsx,xls,docx',
				success: (files) => {
					this.uploadedFiles = [...this.uploadedFiles, ...files];
					this.autoUploadFiles(files)
				},
				fail: (err) => {
					uni.showToast({
						title: '选择文件失败',
						icon: 'none'
					})
				}
			})
		},
		autoUploadFiles(newFiles) {
			newFiles.forEach(f => this.uploadFile(f))
		},
		uploadFile(file) {
			const uploadUrl = `${config.baseUrl}/forest/monitorTask/importData`
			if (!this.$refs.lsjUploadRef || !this.$refs.lsjUploadRef.upload) return
			this.$refs.lsjUploadRef.upload({
				file: file,
				url: uploadUrl,
				name: 'file',
				method: 'post',
				header: {
					Authorization: 'Bearer ' + uni.getStorageSync('App-Token')
				},
				formData: {},
				onprogress: (e) => {
					file.status = 'progress';
					file.progress = e.progress || 0
				},
				success: (e) => {
					file.status = 'success';
					// 兼容不同上传插件返回：有的在 e.data，有的直接在 e
					let payload = e && (e.data || e)
					// 尝试解析字符串
					try {
						if (typeof payload === 'string') payload = JSON.parse(payload)
					} catch (err) {
						// 解析失败，保持原样
					}
					// 有些接口会把结果包一层在 result 字符串里
					if (payload && payload.result && typeof payload.result === 'string') {
						try {
							payload = JSON.parse(payload.result)
						} catch (err) {
							// ignore
						}
					}
					file.response = payload
					// 解析后端返回并渲染表格（仅在解析出数组数据时）
					const parsed = this.parseUploadResult(payload)
					if (parsed && Array.isArray(parsed) && parsed.length > 0) {
						this.allocations = parsed
						// 确保每组 sum 正确
						this.allocations.forEach(g => this.recalcGroupSum(g))
						this.allocationsFromUpload = true
					}
					uni.showToast({
						title: '文件上传成功',
						icon: 'success'
					})
				},
				fail: (e) => {
					file.status = 'fail';
					uni.showToast({
						title: '文件上传失败',
						icon: 'none'
					})
				}
			})
		},
		removeFile(index) {
			if (this.uploadedFiles && index > -1 && index < this.uploadedFiles.length) {
				const file = this.uploadedFiles[index];
				if (this.$refs.lsjUploadRef && this.$refs.lsjUploadRef.deleted) this.$refs.lsjUploadRef.deleted(file);
				this.uploadedFiles.splice(index, 1);
				this.uploadedFiles = [...this.uploadedFiles]
			}
		},
		onYearConfirm(e) {
			this.submitForm.year = e.value[0];
			this.showYearPicker = false
		},
		onCategoryConfirm(e) {
			this.submitForm.category = e.value[0];
			this.showCategoryPicker = false
		},
		onLevelConfirm(e) {
			if (!this.isLevelReadonly) this.submitForm.level = e.value[0];
			this.showLevelPicker = false
		},
		onPickerCancel(name) {
			if (name === 'year') this.showYearPicker = false;
			if (name === 'category') this.showCategoryPicker = false;
			if (name === 'level') this.showLevelPicker = false
		},
		addRule(pi) {
			this.products[pi].rules.push({
				item: '',
				limit: '',
				standard: '',
				method: ''
			})
		},
		removeRule(pi, ri) {
			this.products[pi].rules.splice(ri, 1);
			uni.showToast({
				title: '已删除',
				icon: 'none'
			})
		},
		async handleConfirmSubmit() {
			try {
				if (!this.submitForm.year) {
					uni.showToast({ title: '请选择监测年份', icon: 'none' });
					return
				}
				if (!this.submitForm.category) {
					uni.showToast({ title: '请选择监测类别', icon: 'none' });
					return
				}
				const uploadingFiles = this.uploadedFiles.filter(f => f.status === 'progress');
				if (uploadingFiles.length > 0) {
					uni.showToast({ title: '还有文件正在上传，请稍候', icon: 'none' });
					return
				}
				const failedFiles = this.uploadedFiles.filter(f => f.status === 'fail');
				if (failedFiles.length > 0) {
					uni.showToast({ title: '有文件上传失败，请重新上传', icon: 'none' });
					return
				}

				// 组装 allocationInfo：按页面显示的列与行原样构建（显示什么就传什么）
				const allocationInfoArr = []
				// 每组逐行展开
				this.allocations.forEach(g => {
					g.rows.forEach(r => {
						// 使用每行的原始键值构造对象
						const rowObj = {}
						g.columns.forEach(col => { rowObj[col] = r[col] === undefined ? '' : r[col] })
						allocationInfoArr.push(rowObj)
					})
				})

				// 反查字典 key（若字典存在，将 label 转回 key）
				const findKeyByLabel = (map, label) => {
					for (const k in map) if (map[k] === label) return k
					return null
				}

				const detTypeKey = findKeyByLabel(this.detectionTypeMap, this.submitForm.category) || this.submitForm.category
				const levelKey = findKeyByLabel(this.levelMap, this.submitForm.level) || this.submitForm.level

				const payload = {
					year: String(this.submitForm.year),
					detectionType: detTypeKey,
					detectionLevel: levelKey,
					city: this.submitForm.category,
					allocationInfo: JSON.stringify(allocationInfoArr)
				}

				console.log('monitorTask payload:', payload)

				// 调用后台接口（async/await）
				let res
				if (this.taskId && this.isEditMode) {
					// 编辑已存在任务，按 userType 调用相应的编辑接口并带上 oldId
					if (this.userType === '1') {
						res = await provicemonitorTaskdetail({ detectionProject: payload.allocationInfo, oldId: this.taskId })
						uni.showToast({
							icon: 'none',
							title: '修改成功'
						})
					} else if (this.userType === '2') {
						res = await shimonitorTaskdetail({ detectionProject: payload.allocationInfo, oldId: this.taskId })
						uni.showToast({
							icon: 'none',
							title: '修改成功'
						})
					}
				} else {
					res = await monitorTask(payload)
					uni.showToast({ title: '任务下发成功', icon: 'success' })
				}
				setTimeout(() => uni.navigateBack(), 600)
				return res
			} catch (err) {
				console.error('monitorTask error', err)
				uni.showToast({ title: err && err.message ? err.message : '失败', icon: 'none' })
				throw err
			}
		},
		handleSaveDraft() {
			const draftData = {
				...this.submitForm,
				files: this.uploadedFiles,
				saveTime: new Date().toLocaleString()
			};
			console.log('保存草稿:', draftData);
			uni.showToast({
				title: '草稿保存成功',
				icon: 'success'
			})
		},
		handleReset() {
			this.submitForm = {
				year: '',
				category: '',
				level: '省级'
			};
			this.uploadedFiles = [];
			if (this.$refs.lsjUploadRef && this.$refs.lsjUploadRef.clear) this.$refs.lsjUploadRef.clear()
		},
		async loadLevelDict() {
			try {
				const res = await request({
					url: '/system/dict/data/type/syl_product_monitor_standard_level',
					method: 'get'
				});
				const rows = Array.isArray(res) ? res : (Array.isArray(res && res.data) ? res.data : []);
				const map = {};
				const options = ['全部'];
				rows.forEach(d => {
					const label = d.dictLabel ?? d.label ?? d.name;
					const sort = d.dictSort ?? d.sort ?? d.dictCode;
					if (sort != null) {
						map[String(sort)] = label || sort;
						options.push(label || sort)
					}
				});
				this.levelMap = map;
				this.levelOptions = options;
				console.log('loadLevelDict rows:', rows)
			} catch (err) {
				console.error('loadLevelDict error', err);
				this.levelMap = {}
			}
		},
		async loadDetectionDict() {
			try {
				const res = await request({
					url: `/system/dict/data/type/${this.detectionTypeDictType}`,
					method: 'get'
				});
				const rows = Array.isArray(res) ? res : (Array.isArray(res && res.data) ? res.data : []);
				const map = {};
				const options = [];
				rows.forEach(d => {
					const label = d.dictLabel ?? d.label ?? d.name;
					const value = d.dictValue ?? d.value ?? d.code;
					if (value != null) {
						map[value] = label || value;
						options.push(label || value)
					}
				});
				this.detectionTypeMap = map;
				this.categoryOptions = options;
				// 若当前未选择 category，自动选第一个有效项（避免 '全部' 导致校验失败）
				if ((!this.submitForm.category || this.submitForm.category === '') && Array.isArray(options) && options.length > 0) {
					this.submitForm.category = options[0]
				}
				console.log('loadDetectionDict rows:', rows)
			} catch (err) {
				console.error('loadDetectionDict error', err);
				this.detectionTypeMap = {}
			}
		},
		formatSize(n) {
			if (!n && n !== 0) return '';
			const kb = n / 1024,
				mb = kb / 1024;
			return mb >= 1 ? (mb.toFixed(1) + ' MB') : (Math.max(kb, 1).toFixed(0) + ' KB')
		},
		getStatusText(status) {
			switch (status) {
				case 'progress':
					return '上传中';
				case 'success':
					return '成功';
				case 'fail':
					return '失败';
				default:
					return '待上传'
			}
		},
		// 将后端返回的任意格式数据解析成页面需要的 allocations 格式（动态列）
		parseUploadResult(payload) {
			console.log('parseUploadResult 输入数据:', payload)
			try {
				let dataArr = []
				if (!payload) {
					console.log('payload 为空，返回空数组')
					return []
				}
				if (Array.isArray(payload)) dataArr = payload
				else if (payload.data && Array.isArray(payload.data)) dataArr = payload.data
				else if (payload.rows && Array.isArray(payload.rows)) dataArr = payload.rows
				else if (payload.result && Array.isArray(payload.result)) dataArr = payload.result
				else if (typeof payload === 'object') dataArr = [payload]

				console.log('解析后的 dataArr:', dataArr)
				if (!Array.isArray(dataArr) || dataArr.length === 0) {
					console.log('dataArr 不是数组或为空，返回空数组')
					return []
				}

				// 统一列集合（保留第一行顺序为主）
				const colOrder = []
				dataArr.forEach(row => {
					if (!row || typeof row !== 'object') return
					Object.keys(row).forEach(k => { if (!colOrder.includes(k)) colOrder.push(k) })
				})

				// 尝试找到分组键（优先承检机构等）
				const groupKeys = ['承检机构', 'org', '机构']
				let groupKey = null
				for (const gk of groupKeys) if (colOrder.includes(gk)) { groupKey = gk; break }

				// 构建分组
				const groupsMap = {}
				dataArr.forEach(raw => {
					if (!raw || typeof raw !== 'object') return
					const key = groupKey ? (raw[groupKey] || '') : ''
					if (!groupsMap[key]) groupsMap[key] = { org: key, rows: [], columns: [...colOrder], sum: {} }
					// 保证每行都有完整的列键
					const row = {}
					colOrder.forEach(c => {
						let v = raw[c]
						// 不自动转换类型，保留上传原始格式（字符串/数字/空）
						row[c] = v === undefined || v === null ? '' : v
					})
					row.editing = false
					row._backup = null
					groupsMap[key].rows.push(row)
				})

				// 计算每组的数值列合计
				Object.keys(groupsMap).forEach(k => {
					const g = groupsMap[k]
					const sums = {}
					g.columns.forEach(col => sums[col] = 0)
					g.rows.forEach(r => {
						g.columns.forEach(col => {
							const val = r[col]
							// 尝试按数值解析但不修改原始显示值
							if (typeof val === 'number' && !isNaN(val)) sums[col] += val
							else if (typeof val === 'string' && /^-?\d+(\.\d+)?$/.test(val.trim())) sums[col] += Number(val.trim())
						})
					})
					g.sum = sums
				})

				const result = Object.keys(groupsMap).map(k => groupsMap[k])
				console.log('parseUploadResult 最终结果:', result)
				return result
			} catch (err) {
				console.error('parseUploadResult error', err)
				return []
			}
		},

		isNumeric(v) {
			return typeof v === 'number' || (typeof v === 'string' && /^-?\d+(\.\d+)?$/.test(v.trim()))
		},

		// 是否是合计列（行级合计列名称常见形式："计"、包含"合计"或"总计"）
		isTotalColumn(col) {
			if (!col) return false
			const name = String(col)
			return name === '计' || name.includes('合计') || name.includes('总计')
		},

		// 开发测试：把附件示例 payload 传入 parseUploadResult 验证解析（发布前可删除）
		__testParseSample() {
			const sample = {
				msg: '操作成功',
				code: 200,
				data: [{ '承检机构': '青岛XXX检测中心', '计': 600, '板栗': 235, '核桃': 115, '枣（不含条数）': 205, '花椒': 45 }]
			}
			const parsed = this.parseUploadResult(sample.data)
			console.log('DEV __testParseSample parsed:', parsed)
			return parsed
		}
		,

		startEditRow(group, rowIndex) {
			if (this.taskId && !this.isEditMode) return
			const row = group.rows[rowIndex]
			if (!row) return
			// 备份当前行用于取消（备份所有列，适应动态列）
			const backup = {}
			group.columns.forEach(c => backup[c] = row[c])
			row._backup = backup
			this.$set(group.rows[rowIndex], 'editing', true)
		},

		onRowFieldChange(e, group, rowIndex, field) {
			// 保留用户输入的原始字符串，显示什么就保存什么
			const rawVal = e && e.target ? e.target.value : e.detail && e.detail.value ? e.detail.value : e
			const row = group.rows[rowIndex]
			if (!row) return
			this.$set(row, field, rawVal)
			// 先联动计算该行的合计列（如存在）
			this.recalcRowTotals(group, rowIndex)
			// 再计算组汇总（不改写显示值）
			this.recalcGroupSum(group)
		},

		recalcRowTotals(group, rowIndex) {
			if (!group || !group.rows || rowIndex < 0 || rowIndex >= group.rows.length) return
			const row = group.rows[rowIndex]
			// 找出该行的合计列
			const totalCols = group.columns.filter(c => this.isTotalColumn(c))
			if (!totalCols.length) return
			// 统计该行中除合计列外的数值之和
			let sum = 0
			group.columns.forEach(col => {
				if (totalCols.includes(col)) return
				const v = row[col]
				if (typeof v === 'number' && !isNaN(v)) sum += v
				else if (typeof v === 'string' && /^-?\d+(\.\d+)?$/.test(v.trim())) sum += Number(v.trim())
			})
			// 将合计值以字符串形式写回各个合计列，保持显示-提交一致
			totalCols.forEach(c => this.$set(row, c, String(sum)))
		},

		saveRowEdit(group, rowIndex) {
			const row = group.rows[rowIndex]
			if (!row) return
			this.$set(row, 'editing', false)
			row._backup = null
			this.recalcGroupSum(group)
		},

		cancelRowEdit(group, rowIndex) {
			const row = group.rows[rowIndex]
			if (!row) return
			if (row._backup) {
				Object.keys(row._backup).forEach(k => this.$set(row, k, row._backup[k]))
				row._backup = null
			}
			this.$set(row, 'editing', false)
			this.recalcGroupSum(group)
		},

		recalcGroupSum(group) {
			if (!group || !group.rows) return
			const sums = {}
			group.columns.forEach(col => sums[col] = 0)
			group.rows.forEach(r => {
				group.columns.forEach(col => {
					const v = r[col]
					if (typeof v === 'number' && !isNaN(v)) sums[col] += v
					else if (typeof v === 'string' && /^-?\d+(\.\d+)?$/.test(v.trim())) sums[col] += Number(v.trim())
				})
			})
			this.$set(group, 'sum', sums)
		},
	}
}
</script>

<style lang="scss" scoped>
.mine-navbar-bg {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;

	z-index: 1;
}

.button {
	background: #23A44B;
	border: 0;
	margin: 20rpx 0;
}

.content {
	padding: 20rpx;
}

.info-card {
	background: #fff;
	border-radius: 12rpx;
	padding: 18rpx;
	box-shadow: 0 6rpx 18rpx rgba(0, 0, 0, 0.06);
	margin-bottom: 14rpx
}

.info-row {
	display: flex;
	justify-content: space-between;
	padding: 6rpx 0;
}

.label {
	color: #666;
	font-size: 28rpx
}

.value {
	color: #333;
	font-size: 28rpx
}

.section {
	margin-top: 6rpx
}

.section-title {
	font-size: 30rpx;
	color: #333;
	margin: 10rpx 0
}

.section-title .dot {
	width: 12rpx;
	height: 12rpx;
	background: #19b35b;
	border-radius: 50%;
	display: inline-block;
	margin-right: 10rpx;
	vertical-align: middle
}

.product {
	margin-bottom: 18rpx
}

.product-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 12rpx;
	background: transparent
}

.product-left {
	display: flex;
	align-items: center
}

.product-avatar {
	width: 44rpx;
	height: 44rpx;
	border-radius: 22rpx;
	background: #eafaf0;
	color: #19b35b;
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 700;
	margin-right: 12rpx
}

.product-name {
	font-weight: 600;
	font-size: 30rpx
}

.add-btn {
	background: #19b35b;
	color: #fff;
	padding: 6rpx 14rpx;
	border-radius: 16rpx;
	font-size: 24rpx
}

.rule-list {
	margin-top: 10rpx
}

.rule {
	background: #f8f8f8;
	padding: 12rpx;
	border-radius: 12rpx;
	margin-top: 10rpx
}

.rule-main {
	display: flex;
	justify-content: space-between;
}

.rule-left {
	flex: 1
}

.rule-title {
	font-weight: 600;
	font-size: 26rpx;
	color: #333;
	margin-bottom: 8rpx
}

.rule-line {
	display: flex;
	color: #888;
	margin-top: 6rpx;
	font-size: 24rpx
}

.rule-line .k {
	width: 45%;
	color: #999
}

.rule-line .v {
	width: 55%;
	color: #666
}

.rule-right {
	width: 56rpx;
	display: flex;
	align-items: flex-start;
	justify-content: center
}

/* 上传文件列表样式调整 */
.file-list {
	display: flex;
	flex-direction: column;
	gap: 12rpx;
	margin-top: 12rpx;
}

.file-item {
	display: flex;
	align-items: center;
	justify-content: space-between;
	background: #fff;
	padding: 12rpx;
	border-radius: 10rpx;
	box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.04);
}

.file-info {
	display: flex;
	align-items: center;
	gap: 12rpx;
	flex: 1;
	overflow: hidden;
}

.file-name {
	flex: 1;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	display: -webkit-box;
	-webkit-line-clamp: 1;
	-webkit-box-orient: vertical;
	line-clamp: 1;
	font-size: 26rpx;
	color: #333;
}

.edit-input {
	width: 100%;
	height: 56rpx;
	padding: 8rpx;
	box-sizing: border-box;
}

.cell.total-readonly {
	color: #999
}

.file-size {
	color: #999;
	font-size: 24rpx;
	margin-left: 8rpx;
}

.file-status {
	width: 180rpx;
	text-align: left;
	color: #666;
	font-size: 24rpx;
	margin-left: 12rpx;
}

.status-success {
	color: #19b35b
}

u-icon[name="close"] {
	margin-left: 10rpx;
}

.delete {
	width: 40rpx;
	height: 40rpx;
	border-radius: 8rpx;
	background: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06)
}

.del-icon {
	font-size: 20rpx;
	color: #999
}

.actions {
	padding: 20rpx;
	height: 120rpx
}

.fixed-actions {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	justify-content: center;
	padding: 24rpx 20rpx 36rpx;
	background: transparent
}

.confirm-btn {
	width: 92%;
	border-radius: 12rpx
}

/* 表格美化 */
.allocations {
	margin-top: 16rpx;
}

.alloc-group {
	margin-bottom: 18rpx;
	background: #fff;
	border-radius: 8rpx;
	overflow: hidden;
	box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}

.group-header {
	background: linear-gradient(90deg, #f3fbf4, #ffffff);
	padding: 14rpx 18rpx;
	font-weight: 700;
	color: #1f5a2e;
	border-left: 4rpx solid #19b35b;
}

.alloc-table {
	width: 100%;
}

.table-row {
	display: flex;
	align-items: center;
	padding: 10rpx 14rpx;
	border-bottom: 1rpx solid #f0f2f5;
}

.table-head {
	background: #fafbfd;
	color: #666;
	font-weight: 600;
}

.table-row:nth-child(even) {
	background: #fff;
}

.cell {
	flex: 1;
	text-align: left;
	font-size: 20rpx;
	color: #333;
}

.cell.org-cell {
	flex: 1.2;
	font-weight: 600;
}

.table-sum {
	background: #f7f9fb;
	font-weight: 600;
}

.link {
	color: #19b35b;
}

.readonly-text {
	color: #999;
	font-size: 20rpx;
}

/* 上传控件美化 */
.upload-controls {
	display: flex;
	align-items: center;
	gap: 12rpx;
	margin-top: 8rpx
}

.u-button.button {
	background: linear-gradient(90deg, #19b35b, #0ea95e);
	border-radius: 8rpx
}

.file-item {
	align-items: center
}
</style>